package get_TSS;

import java.util.List;

import tf_rna_hit.Bed;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

/**
 * 
 * @author ygidtu
 *
 *	用来提取lncRNA的TSS位点，定义为匹配转录本第一个exon的第一个碱基
 *	一共两个文件，第一个是待处理的lncRNA六列的bed文件
 *	第二个文件是提取出来的六列的注释文件
 *	然后按照位点比对转录本，覆盖度最大的，作为我们的目标转录本
 */

public class GetTSS {
	public static void main(String args[]){
		if(args[0].equals("-h") || args[0].equals("--help") || args.length == 0){
			System.out.println("用来提取lncRNA的TSS位点，定义为匹配转录本第一个exon的第一个碱基");
			System.out.println("一共两个文件，第一个是待处理的lncRNA六列的bed文件");
			System.out.println("第二个文件是提取出来的六列的注释文件");
			System.out.println("然后按照位点比对转录本，覆盖度最大的，作为我们的目标转录本");
			System.out.println("待转换文件的第四列是用来寻找匹配的标识");
		}
		try{
			// 新建两个文件
			File file0 = new File(args[0]);
			File file1 = new File(args[1]);
			
			// 分别判断两个文件是否存在，并读取
			
			if(file0.exists() && file0.isFile()){
				System.out.println("开始读取文件:" + args[0]);
			}else{
				System.out.println(args[0] + "文件不存在");
				return;
			}
			
			// 新建一批变量，用来储存读取的内容
			String content = null;
			List chr = new ArrayList();
			List start = new ArrayList();
			List end = new ArrayList();
			List strand = new ArrayList();
			List name = new ArrayList();
			List label = new ArrayList();
			
			FileReader fr0 = new FileReader(file0);
			BufferedReader br0 = new BufferedReader(fr0);
			
			// 第一个文件读取
			while((content = br0.readLine()) != null){
				String[] contentarray = content.split("\\s+");
				if(contentarray.length == 6){
					chr.add(contentarray[0]);
					start.add(contentarray[1]);
					end.add(contentarray[2]);
					name.add(contentarray[3]);
					label.add(contentarray[4]);
					strand.add(contentarray[5]);
				}else{
					chr.add(contentarray[0]);
					start.add(contentarray[1]);
					end.add(contentarray[2]);
					name.add(contentarray[3]);
					label.add("NA");
					strand.add(contentarray[4]);
				}
				
			}
			// 文件转储
			Bed[] lncrna = new Bed[chr.size()];
			
			for(int i = 0; i < chr.size(); i++){
				lncrna[i] = new Bed(chr.get(i).toString(), Integer.parseInt(start.get(i).toString()),
						Integer.parseInt(end.get(i).toString()), name.get(i).toString(), 
						label.get(i).toString(), strand.get(i).toString());
			}
			
			br0.close();
			fr0.close();
			
			System.out.println(args[0] + "读取完成");
			
			if(file1.exists() && file1.isFile()){
				System.out.println("开始读取文件:" + args[1]);
			}else{
				System.out.println(args[1] + "文件不存在");
				return;
			}
			
			// 清空list，准备读取第二个文件
			chr.clear();
			start.clear();
			end.clear();
			name.clear();
			label.clear();
			strand.clear();
			
			FileReader fr1 = new FileReader(file1);
			BufferedReader br1 = new BufferedReader(fr1);
			
			// 文件读取
			while((content = br1.readLine()) != null){
				String[] contentarray = content.split("\\s+");
				
				chr.add(contentarray[0]);
				start.add(contentarray[1]);
				end.add(contentarray[2]);
				name.add(contentarray[3]);
				label.add(contentarray[4]);
				strand.add(contentarray[5]);
			}
			
			// 文件转储
			Bed[] tss = new Bed[chr.size()];
			
			for(int i = 0; i < chr.size(); i++){
				tss[i] = new Bed(chr.get(i).toString(), Integer.parseInt(start.get(i).toString()),
						Integer.parseInt(end.get(i).toString()), name.get(i).toString(), 
						label.get(i).toString(), strand.get(i).toString());
			}
			
			br1.close();
			fr1.close();
			
			// 清空list，应该可以节省内存，而且有可能待会还要使用
			chr.clear();
			start.clear();
			end.clear();
			name.clear();
			label.clear();
			strand.clear();
			
			System.out.println(args[1] + "读取完成");
			
			Bed[] results = get_tss(lncrna, tss);
			
			if(results.length == 0){
				System.out.println("没有匹配，程序终止");
				return;
			}
			
			// 开始准备输出
			File output = new File(args[2]);
			
			if(output.exists() && output.isFile()){
				System.out.println("使用已经存在的文件" + output);
			}else{
				try{
					output.createNewFile();
					System.out.println("创建新文件");
				}catch (IOException e){
					System.out.println("创建文件失败，错误信息：" + e.getMessage());
					return;
				}
			}
			
			FileWriter fw = new FileWriter(output);
			BufferedWriter bw = new BufferedWriter(fw);
			
			for(int i = 0; i < results.length; i++){
				bw.write(results[i].printBed());
				bw.newLine();
			}
			
			bw.close();
			fw.close();
			
		}catch(FileNotFoundException e){ // 这部分是输入时候的异常，前边的代码嵌套在他里边，这里基本把异常沉默掉了，不输出
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	
////////////////////////////////////         私有方法			///////////////////////////////////////////////////////
	private static Bed[] get_tss(Bed[] lnc, Bed[] tss){
		Bed[] results;
		List coverage = new ArrayList();
		List covpos = new ArrayList();
		List rnapos = new ArrayList();
		List tsspos = new ArrayList();
		
		// 两个循环遍历所有的bed
		for(int i = 0; i < lnc.length; i++){
			for(int j = 0; j < tss.length; j++){	// 一个判断，染色体、名字和正负链都对应的上，并且tss的tag为transcript才进行下一步比较
				if(lnc[i].getChr().equals(tss[j].getChr()) && 
						lnc[i].getTag().equals(tss[j].getName()) && 
						lnc[i].getStrand().equals(tss[j].getStrand())
						&& tss[j].getTag().equals("transcript")){
					
					// 这里需要嵌套另外一个判断，用来计算覆盖度
					if(lnc[i].getStart() <= tss[j].getEnd() && 
							lnc[i].getEnd() >= tss[j].getStart()){
						
						coverage.add(lnc[i].getEnd() - tss[j].getStart());
						covpos.add(j);
						
					}else if(lnc[i].getEnd() >= tss[j].getEnd() && lnc[i].getStart() <= tss[j].getEnd()){
						
						coverage.add(tss[j].getEnd() - lnc[i].getStart());
						covpos.add(j);
						
					}
				}
			}
			
			// 内层循环完成，用来提取最大值
			if(covpos.size() > 0){
				rnapos.add(i);
				tsspos.add(covpos.get(whichMax(coverage)));
			}
			
			covpos.clear();
			coverage.clear();
		}
		
		results = new Bed[rnapos.size()];
		// 最后转储结果
		for(int i = 0; i < rnapos.size(); i++){
			results[i] = new Bed(lnc[Integer.parseInt(rnapos.get(i).toString())].getChr(),
					lnc[Integer.parseInt(rnapos.get(i).toString())].getStart(),
					lnc[Integer.parseInt(rnapos.get(i).toString())].getEnd(),
					lnc[Integer.parseInt(rnapos.get(i).toString())].getName(),
					Integer.toString(tss[Integer.parseInt(tsspos.get(i).toString()) + 1].getStart()),
					lnc[Integer.parseInt(rnapos.get(i).toString())].getStrand());
		}
		
		return results;
	}
	// 用来返回List中最大值的下角标
	private static int whichMax(List input){
		int which = 0;		
		for(int i = 0; i < input.size() - 1; i++){
			if(Integer.parseInt(input.get(i).toString()) >= Integer.parseInt(input.get(i + 1).toString())){
				which = i;
			}else{
				which = i+1;
			}
		}
		return which;
	}
}
